/*
	gorefit themes websites by replacing, removing and appending XPath nodes.
*/
package gorefit

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"
)

type refitparser func(s *Server)

type Server struct {
	In  *Document
	Out *Document

	backendurl       string
	frontendhostport string
	parser           func(r *Server)
	template         string
	fileServer       http.Handler
}

func NewServer(backendurl string, frontendhostport string, parser refitparser) *Server {
	s := new(Server)

	s.backendurl = backendurl
	s.frontendhostport = frontendhostport
	s.parser = parser

	if s.fileServer == nil {
		wd, _ := os.Getwd()
		s.fileServer = http.FileServer(http.Dir(wd + "/static"))
	}
	return s
}

func (self *Server) SetTemplate(filename string) error {
	file, err := os.Open(filename)
	if err != nil {
		self.Out.PushMessage(NewError(err.Error()))
		return err
	}
	defer file.Close()
	sbuff := bytes.NewBuffer(make([]byte, 0))
	buff := make([]byte, 1024)
	for {
		n, err := file.Read(buff)
		if err != nil && err != io.EOF {
			self.Out.PushMessage(NewError(err.Error()))
			return err
		}
		if n == 0 {
			break
		}
		sbuff.Write(buff[:n])
	}
	self.template = sbuff.String()
	if self.Out != nil {
		self.Out.SetBody(self.template, false)
	}
	self.Out.PushMessage(NewDebug("Setting template to file \"" + filename + "\""))
	//	self.Out.PushMessage(NewDebug("Setting template to \"" + html.EscapeString(self.template) + "\"</textarea>"))
	return nil
}

func (self *Server) Serve() {
	fmt.Println("Refit serving on " + self.frontendhostport)
	s := &http.Server{
		Addr:           self.frontendhostport,
		Handler:        self,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(s.ListenAndServe())
}

func (self *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Serving " + r.URL.Path)
	if len(r.URL.Path) > 6 && r.URL.Path[0:7] == "/static" {
		r.URL.Path = r.URL.Path[7:]
		self.fileServer.ServeHTTP(w, r)
	} else {
		resp, err := http.Get(self.backendurl + r.URL.RequestURI())
		if err != nil {
			w.Write([]byte("RefitServer.ServeHTTP contacting backend: " + err.Error()))
		} else {
			defer resp.Body.Close()
			body, _ := ioutil.ReadAll(resp.Body)
			self.In = new(Document)
			self.In.SetBody(string(body), false)

			if resp.Status[:3] == "404" { // Handle not found
				w.WriteHeader(http.StatusNotFound)
				w.Write([]byte("404 not found"))
			} else if len(resp.Header.Get("Content-Type")) < 9 || resp.Header.Get("Content-Type")[:9] != "text/html" { // Handle other Content-Type
				for key, values := range resp.Header {
					w.Header().Del(key)
					for _, value := range values {
						w.Header().Add(key, value)
					}
				}
				w.Write([]byte(body))
			} else { // Parse HTML. Reload template each time. TODO: Make this a command line option
				self.Out = new(Document)
				self.parser(self)
				w.Write([]byte(self.Out.String()))
				/*				err := self.loadTemplateFile("template.html")
								if err != nil {
									w.Write([]byte("RefitServer.ServeHTTP loading template: " + err.Error()))
								} else {
									tmpl, err := template.New("template").Parse(self.template)
									if err != nil {
										w.Write([]byte("RefitServer.ServeHTTP parsing template: " + err.Error()))
									} else {
										doc, err := self.getDoc(resp)
										if err != nil {
											w.Write([]byte("RefitServer.ServeHTTP parsing backend: " + err.Error()))
										} else {
											p := NewParser(doc)
											tmpl.Execute(w, p)
										}
									}
								}*/
			}
		}
	}
}

func (self *Server) HTMLMessages(level int) string {
	result := "<table style=\"border: 1px solid black\">"

	result += "<tr><td colspan=\"3\"><h2>Input document</h2></td></tr>"
	for msg := self.In.PopMessage(); msg != nil; msg = self.In.PopMessage() {
		if msg.Type >= level {
			result += msg.HTMLRow()
		}
	}

	result += "<tr><td colspan=\"3\"><h2>Output document</h2></td></tr>"
	for msg := self.Out.PopMessage(); msg != nil; msg = self.Out.PopMessage() {
		if msg.Type >= level {
			result += msg.HTMLRow()
		}
	}

	result += "</table>"

	return result
}
